#!/usr/bin/env python
# -*- coding: utf-8 -*-

import thread

from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import QWidget, QLabel, QPixmap, QGridLayout
from PyQt4.QtCore import SIGNAL, Qt, QTimeLine, QPoint

import cardface_rc

#9个方位
N, S, W, E, NW, NE, SW, SE, C=range(9)

class ScoreBoxWidget(object):
    '''积分盒控件（管理）'''
    def __init__(self, wScoreList):
        #初始化积分盒控件（QLabel）列表
        self.wScoreList=wScoreList
        #有效积分盒位置列表
        self.availScores=range(9)
    
    def setAvailScores(self, availScores):
        '''设置有效积分盒'''
        self.availScores=availScores

    def setScore(self, dirc, score):
        '''设置某方向的积分盒分值'''
        self.wScoreList[dirc].setText(str(score))
        
    def initScoreWidgets(self, initscore=0):
        '''初始化积分盒'''
        for w in self.wScoreList:
            w.setText('')
        for i in self.availScores:
            self.wScoreList[i].setText(str(initscore))
    
    
class TableWidget(QLabel):
    '''牌桌控件'''
    def __init__(self, parent = None):
        super(TableWidget, self).__init__(parent,)
        self.pWidget=parent
    
    def resizeEvent(self, event):
        '''大小改变事件，重绘各玩家Widget'''
        self.pWidget.showWPlayerList()
        self.pWidget.moveWAction()
        self.pWidget.moveWToken()

CARDWIDTH=71
CARDHEIGHT=96
class CardWidget(QLabel):
    '''牌控件'''
    def __init__(self, parent = None, id=None, scale=1):
        super(CardWidget, self).__init__(parent)
        #牌id
        self.id=id
        #放大系数
        self.scale=scale
        
        if self.id is not None:
            #设置id对应的牌面
            self.pixFront=QPixmap(':/rc/card/%d.png'%self.id)
        else:
            #无id则设置白面
            self.pixFront=QPixmap(':/rc/card/white.png')
        #设置牌背图案
        self.pixRear=QPixmap(':/rc/card/100.png')
        
        #正反面状态，正面为真
        self.front=False
        #突出状态，突出为真
        self.standOut=False
        #默认显示反面
        self.turnRear()
        #关闭时删除
        self.setAttribute(Qt.WA_DeleteOnClose)
        
        #设置图片填充整个控件并调整控件大小
        self.setScaledContents(True)
#        self.resize(CARDWIDTH*self.scale, CARDHEIGHT*self.scale)
        self.setFixedSize(CARDWIDTH*self.scale, CARDHEIGHT*self.scale)

    def setRearPix(self, pix):
        '''设置牌背图片'''
        self.pixRear=pix
    
    def turnFront(self):
        '''显示牌面'''
        self.setPixmap(self.pixFront)
        self.front=True
    
    def turnRear(self):
        '''显示牌背'''
        self.setPixmap(self.pixRear)
        self.front=False
    
    def showText(self, text):
        '''显示文字'''
        self.setText(text)
        self.setAlignment(Qt.AlignCenter)
        
    def moveOut(self):
        '''突出牌'''
        if not self.standOut:
            rect=self.geometry()
            self.move(rect.x(), rect.y()-15)
            self.standOut=True
    
    def moveBack(self):
        '''撤回牌'''
        if self.standOut:
            rect=self.geometry()
            self.move(rect.x(), rect.y()+15)
            self.standOut=False
    
    def mousePressEvent(self, event):
        '''鼠标按下事件'''
        button=event.button()
        if button==Qt.LeftButton:
            #按左键
            if self.front:
                #正面，切换突出状态
                if self.standOut:
                    self.moveBack()
                else:
                    self.moveOut()
            else:
                #反面，切换背景
                import random
                self.setRearPix(QPixmap(':/rc/card/%d.png'%(random.choice(range(100, 111)))))
                self.turnRear()
        elif button==Qt.RightButton:
            #按右键，切换正反面
            if self.front:
                self.turnRear()
            else:
                self.turnFront()

SCARDWIDTH=32
SCARDHEIGHT=50
class SCardWidget(QLabel):
    '''小牌控件，精简版的牌，只显示用'''
    def __init__(self, parent = None, id=None, scale=1):
        super(SCardWidget, self).__init__(parent)
        #牌id
        self.id=id
        #放大系数
        self.scale=scale
        
        #设置牌面图片
        self.setPixmap(QPixmap(':/rc/scard/%d.png'%self.id))
        #设置图片填充整个控件并调整控件大小
        self.setScaledContents(True)
        self.setFixedSize(SCARDWIDTH*self.scale, SCARDHEIGHT*self.scale)
        #关闭时删除
        self.setAttribute(Qt.WA_DeleteOnClose)


class SCardListWidget(QWidget):
    '''小牌列表控件，装小牌'''
    def __init__(self, parent = None, rLimit=5, cardScale=1/2.0):
        super(SCardListWidget, self).__init__(parent)
        #行牌数限制
        self.rLimit=rLimit
        #小牌Widget列表
        self.wSCards=[]
        #牌放大系数
        self.cardScale=cardScale
        #采用的栅格布局
        self.layout=QGridLayout(self)
        self.layout.setSpacing(0)
        self.layout.setMargin(0)
        
    def clear(self):
        '''清除小牌Widget等资源'''
        for cw in self.wSCards:
            cw.close()
        self.wSCards=[]
    
    def setSCards(self, cards):
        '''装入小牌到列表'''
        self.clear()
        for c in cards:
            cw=SCardWidget(self, c, self.cardScale)
            self.wSCards.append(cw)
    
    def orderSCards(self):
        '''整理小牌列表，调整布局'''
        i=j=0
        for cw in self.wSCards:
            self.layout.addWidget(cw, i, j)
            j+=1
            if j==self.rLimit:
                i+=1
                j=0
    
    def calcSize(self):
        '''计算Widget大小'''
        count=len(self.wSCards)
        rowCount=count/self.rLimit
        if count%self.rLimit:
            rowCount+=1
        colCount=count if count<self.rLimit else self.rLimit
        width=colCount*self.cardScale*SCARDWIDTH
        height=rowCount*self.cardScale*SCARDHEIGHT
        return width, height

    def show(self):
        for cw in self.wSCards:
            cw.show()
        super(SCardListWidget, self).show()
        self.raise_()
        self.adjustSize()

class PlayerWidget(QWidget):
    '''玩家控件'''
    def __init__(self, parent = None, dirc=None, info={}):
        super(PlayerWidget, self).__init__(parent)
        #父Widget（牌桌）
        self.pWidget=self.parentWidget()
        #玩家信息
        self.info=info
        #座位方向
        self.dirc=dirc
        #出牌位坐标
        self.coordPlay=[0, 0]
        #拿牌位（牌盒）坐标
        self.coordTake=[0, 0]
        #个人信息标签坐标
        self.coordInfo=[0, 0]
        #收牌列表坐标
        self.coordInList=[0, 0]
        #个人信息标签
        self.infoWidget=QLabel(self.pWidget)
        self.infoWidget.setAttribute(Qt.WA_DeleteOnClose)
        self.infoWidget.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        #个人信息标签样式，0为纵向，1为横向
        self.infoStyle=0
        #收牌列表Widget
        self.inListWidget=SCardListWidget(self.pWidget)
        self.inListWidget.setToolTip(u'收牌列表')
        #标志（用牌背来代替）
        self.logo=CardWidget(self)
        #出牌Widget列表
        self.outWCards=[]
        #持牌数
        self.cardCount=0

        #牌Widget（演示动画用牌）
        self.cardWidgetAm=CardWidget(self.pWidget)
        self.cardWidgetAm.setAttribute(Qt.WA_DeleteOnClose)
        self.cardWidgetAm.hide()
        #拿牌动画
        self.ma=None

        self.adjustSize()
        #关闭时删除
        self.setAttribute(Qt.WA_DeleteOnClose)
    
    def clear(self):
        '''释放所有资源'''
        self.clearOutWCards()
        self.infoWidget.close()
        self.cardWidgetAm.close()
        self.inListWidget.clear()
        self.close()
    
    def sit(self):
        '''按方位座下'''
        #父Widget矩形
        prect=self.pWidget.geometry()
        #自身矩形
        rect=self.geometry()
        #信息标签矩形
        self.updateWInfo()
        irect=self.infoWidget.geometry()
        #收牌列表宽高
        ilWidth, ilHeight=self.inListWidget.calcSize()
        #设置牌盒坐标为中央
        self.coordTake=[(prect.width()-rect.width())/2, (prect.height()-rect.height())/2]
        #logo离边距离
        offset=15
        #出牌位与logo距离
        poffset=130
        #信息标签与logo距离
        ioffset=5
        #收牌列表间隔距离
        iloffset=5
        if self.dirc==N:
            x=(prect.width()-rect.width())/2
            y=offset
            self.coordPlay=[x, poffset]
            self.coordInfo=[x+rect.width()+ioffset, y]
            self.coordInList=[self.coordInfo[0], y+irect.height()+iloffset]
            self.inListWidget.rLimit=4
        elif self.dirc==S:
            x=(prect.width()-rect.width())/2
            y=prect.height()-rect.height()-offset
            self.coordPlay=[x, prect.height()-rect.height()-poffset]
            self.coordInfo=[(prect.width()-irect.width())/2, prect.height()-irect.height()]
            self.coordInList=[self.coordInfo[0]+irect.width()+iloffset, prect.height()-ilHeight]
            self.inListWidget.rLimit=7
        elif self.dirc==W:
            x=offset
            y=(prect.height()-rect.height())/2
            self.coordPlay=[poffset, y]
            self.coordInfo=[x, y-irect.height()-ioffset]
            self.coordInList=[x, y+rect.height()+iloffset]
            self.inListWidget.rLimit=4
        elif self.dirc==E:
            x=prect.width()-rect.width()-offset
            y=(prect.height()-rect.height())/2
            self.coordPlay=[prect.width()-rect.width()-poffset, y]
            self.coordInfo=[x, y-irect.height()-ioffset]
            self.coordInList=[x, y+rect.height()+iloffset]
            self.inListWidget.rLimit=4
        elif self.dirc==SE:
            x=prect.width()-rect.width()-offset
            y=prect.height()-rect.height()-offset
            self.coordPlay=[prect.width()-rect.width()-poffset, prect.height()-rect.height()-poffset]
            self.coordInfo=[x, y-irect.height()-ioffset]
            self.coordInList=[x-ilWidth-iloffset, y+rect.height()-ilHeight]
            self.inListWidget.rLimit=4
        elif self.dirc==SW:
            x=offset
            y=prect.height()-rect.height()-offset
            self.coordPlay=[poffset, prect.height()-rect.height()-poffset]
            self.coordInfo=[x, y-irect.height()-ioffset]
            self.coordInList=[x+rect.width()+iloffset, y+rect.height()-ilHeight]
            self.inListWidget.rLimit=4
        elif self.dirc==NE:
            x=prect.width()-rect.width()-offset
            y=offset
            self.coordPlay=[prect.width()-rect.width()-poffset, poffset]
            self.coordInfo=[x-irect.width()-ioffset, y]
            self.coordInList=[x-ilWidth-ioffset, y+irect.height()+iloffset]
            self.inListWidget.rLimit=4
        elif self.dirc==NW:
            x=offset
            y=offset
            self.coordPlay=[poffset, poffset]
            self.coordInfo=[x+rect.width()+ioffset, y]
            self.coordInList=[self.coordInfo[0], y+irect.height()+iloffset]
            self.inListWidget.rLimit=6
        self.move(x, y)

    def show(self):
        '''显示所有附属Widget'''
        QWidget.show(self)
        self.showOutWCards()
        self.showWInfo()
        self.showInList()
        
    def updateWInfo(self, **info):
        '''更新信息标签'''
        if self.infoStyle==0:
            sep=u'\n'
        elif self.infoStyle==1:
            sep=u'  '
        
        val=info.get('cardCount')
        if val is not None:
            self.cardCount=val
        cardCount=self.cardCount
        name=self.info.get('name')
        id=self.info.get('id')
        role=self.info.get('role')

        textDesc=[u'玩家: %s', u'ID: %d', u'牌数: %d', u'角色: %s']
        textVal=[name, id, cardCount, role]
        #有效项目
        items=[]
        
        for i in range(len(textDesc)):
            val=textVal[i]
            if val is not None:
                items.append(textDesc[i]%val)

        text=sep.join(items)
        self.infoWidget.setText(text)
        self.infoWidget.adjustSize()

    def showWInfo(self):
        '''显示信息标签'''
        self.infoWidget.move(*self.coordInfo)
        self.infoWidget.show()
    
    def updateInList(self, cards):
        '''更新收牌列表'''
        self.inListWidget.setSCards(cards)
        self.inListWidget.orderSCards()
    
    def showInList(self, on=True):
        '''显示收牌列表'''
        if on:
            self.inListWidget.move(*self.coordInList)
            self.inListWidget.show()
        else:
            self.inListWidget.hide()
    
    def showOutWCards(self):
        '''显示出牌Widget'''
        count=len(self.outWCards)
        if not count:
            return
        #水平间距
        xdelta=14
        #垂直间距
        ydelta=30
        #行牌数限制
        rlimit=5
        x0, y=self.coordPlay
        if count<rlimit:
            x0=x0-xdelta*(count-1)/2
        else:
            x0=x0-xdelta*(rlimit-1)/2
        i=0
        x=x0
        for cw in self.outWCards:
            cw.moveBack()
            cw.move(x, y)
            cw.show()
            cw.raise_()
            x+=xdelta
            i+=1
            if i==rlimit:
                i=0
                x=x0
                y+=ydelta

    def clearOutWCards(self):
        '''清空出牌Widget'''
        for cw in self.outWCards:
            cw.close()
        self.outWCards=[]

    def playWCard(self, cards, am=True, timeout=100):
        '''出牌'''
        self.clearOutWCards()
        if not cards:
            #显示不出牌（出空牌）
            cw=CardWidget(self.pWidget)
            cw.showText(u'不出')
            self.outWCards.append(cw)
            self.showOutWCards()
        else:
            for card in cards:
                cw=CardWidget(self.pWidget, card)
                cw.turnFront()
                self.outWCards.append(cw)
            #出牌动画
            if am:
                self.playWCardAm(timeout)
            else:
                self.playWCardFinished()
    
    def playWCardAm(self, timeout=100):
        '''出牌，动画'''
        self.ma=MoveAnimation(self.cardWidgetAm, self.pos(), QPoint(*self.coordPlay),
                                timeout, self.playWCardFinished)
        self.ma.start()
        self.cardWidgetAm.show()
        self.cardWidgetAm.raise_()
    
    def playWCardFinished(self):
        '''出牌动画结束的收尾工作'''
        self.cardWidgetAm.hide()
        self.showOutWCards()

    def takeWCard(self, am=True, timeout=100):
        '''拿牌'''
        if am:
            self.takeWCardAm(timeout)
        else:
            self.takeWCardFinished()
    
    def takeWCardAm(self, timeout=100):
        '''拿牌，动画'''
        self.ma=MoveAnimation(self.cardWidgetAm, QPoint(*self.coordTake), self.pos(), 
                                timeout, self.takeWCardFinished)
        self.ma.start()
        self.cardWidgetAm.show()
        self.cardWidgetAm.raise_()
    
    def takeWCardFinished(self):
        '''拿牌结束的收尾工作'''
        self.cardWidgetAm.hide()
    
    def showWCard(self, cards):
        '''亮牌'''
        self.clearOutWCards()
        if not cards:
            #显示不出牌（出空牌）
            cw=CardWidget(self.pWidget)
            cw.showText(u'不亮')
            self.outWCards.append(cw)
        else:
            for card in cards:
                cw=CardWidget(self.pWidget, card)
                cw.turnFront()
                self.outWCards.append(cw)
        self.showOutWCards()


class LPlayerWidget(PlayerWidget):
    '''本地玩家控件，拥有持牌Widget列表'''
    def __init__(self, parent = None, dirc=S, info={}):
        super(LPlayerWidget, self).__init__(parent, dirc, info)
        #隐藏logo
        self.logo.hide()
        #持牌Widget列表
        self.wCardList=[]
        #牌大小顺序（牌序）
        self.cardOrder=range(54)
        #操作Widget坐标
        self.coordAction=[0, 0]
        #个人信息标签样式，本地玩家为横向
        self.infoStyle=1
    
    def clear(self):
        '''释放所有资源'''
        super(LPlayerWidget, self).clear()
        self.clearWCardList()
    
    def setCardOrder(self, order):
        '''设置牌序'''
        self.cardOrder=order
    
    def addWCard(self, cards):
        '''添加牌Widget到持牌Widget列表'''
        for i in cards:
            cw=CardWidget(self.pWidget, i)
            cw.turnFront()
            self.wCardList.append(cw)
        self.orderWCardList()
    
    def clearWCardList(self):
        '''清除持牌Widget列表'''
        for cw in self.wCardList:
            cw.close()
        self.wCardList=[]
    
    def orderWCardList(self):
        '''整理持牌Widget列表'''
        self.wCardList.sort(key=lambda x:self.cardOrder[x.id], reverse=True)
    
    def showWCardList(self):
        '''显示持牌Widget列表'''
        #父Widget（牌桌）矩形
        rect=self.pWidget.geometry()
        #牌片宽度和高度
        cwidth=CARDWIDTH
        cheight=CARDHEIGHT
        #牌计数
        ccount=len(self.wCardList)
        #水平间距
        xdelta=20
        if ccount>20:
            xdelta=15
        #垂直间距
        ydelta=30
        #离底部偏移
        offset=20
        
        #每行牌数
        step=28
        y=rect.height()-cheight-ydelta*(ccount/step)-offset
        
        #保存牌列表顶部中点坐标，用于显示相关操作
        self.coordAction=[rect.width()/2, y]
        
        for i in range(0, ccount, step):
            rowcards=self.wCardList[i:i+step]
            x=(rect.width()-(cwidth+xdelta*len(rowcards)))/2
            for cw in rowcards:
                cw.move(x, y)
                if cw.standOut:
                    #保持牌突出状态
                    cw.standOut=False
                    cw.moveOut()
                x+=xdelta
                cw.show()
                cw.raise_()
            y+=ydelta

    def show(self):
        '''显示所有附属Widget，顺序有所不同'''
        QWidget.show(self)
        self.showOutWCards()
        self.showWCardList()
        self.showWInfo()
        self.showInList()

    def playWCard(self, cards, am=True, timeout=100):
        '''出牌，与一般不同，牌Widget来自持牌列表'''
        self.clearOutWCards()
        if not cards:
            #显示不出牌（出空牌）
            if not cards:
                cw=CardWidget(self.pWidget)
                cw.showText(u'不出')
                self.outWCards.append(cw)
                self.showOutWCards()
        else:
            for card in cards:
                #找到card对应的CardWidget
                for cw in self.wCardList:
                    if cw.id==card:
                        break
                self.wCardList.remove(cw)
                self.outWCards.append(cw)
            #整理突出状态
            for cw in self.wCardList:
                cw.moveBack()
            #出牌动画
            if am:
                self.playWCardAm(timeout)
            else:
                self.playWCardFinished()
        #最后要更新持牌列表
        self.showWCardList()

    def takeWCardFinished(self):
        '''拿牌结束的收尾工作'''
        super(LPlayerWidget, self).takeWCardFinished()
        self.showWCardList()
    
    def getStandOutWCardList(self):
        '''获取突出的牌Widget列表'''
        wcards=[]
        for cw in self.wCardList:
            if cw.standOut:
                wcards.append(cw)
        return wcards


class MoveAnimation(object):
    '''移动动画类'''
    def __init__(self, widget, p0, pn, duration=1000, func=None):
        #动画Widget对象、起始坐标点、终止坐标点
        self.widget, self.p0, self.pn=widget, p0, pn
        #时间线对象
        self.timeline=QTimeLine(duration)
        #设置帧范围，这里最大设为间隔
        self.timeline.setFrameRange(0, duration)
        #保存最大范围
        self.maxRange=duration
        #结束时调用的函数
        self.finished=func
        #连接相关信号槽
        self.widget.connect(self.timeline, SIGNAL('frameChanged(int)'), self.move)
        if self.finished:
            self.widget.connect(self.timeline, SIGNAL('finished()'), self.finished)
    
    def move(self, percent):
        '''槽，每一帧的移动动作'''
        x0, y0=self.p0.x(), self.p0.y()
        xn, yn=self.pn.x(), self.pn.y()
        dx=(xn-x0)*percent/self.maxRange
        dy=(yn-y0)*percent/self.maxRange
        self.widget.move(x0+dx, y0+dy)
    
    def start(self):
        '''开始动画'''
        self.widget.move(self.p0)
        self.timeline.start()
        
    def setDuration(self, duration):
        '''设置动画持续时间'''
        self.timeline.setDuration(duration)
    
    def setUpdateInterval(self, interval):
        '''设置更新间隔'''
        self.timeline.setUpdateInterval(interval)

if __name__ == "__main__":
    import sys
    app=QtGui.QApplication(sys.argv)
    w=PlayerWidget()
    w.show()
    c=CardWidget(id=53, scale=1/3.0)
    c.turnFront()
    c.show()
    sc=SCardWidget(id=20, scale=1/2.0)
    sc.show()
    
    sc=SCardListWidget()
    sc.setSCards(range(13))
    sc.orderSCards()
#    sc.setSCards(range(10))
#    sc.orderSCards()
    sc.show()
    
    sys.exit(app.exec_())
